
/*
 *
 * Copyright (C) 2008 Mattias Blomqvist, patr-blo at dsv dot su dot se
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
//using System.Windows.Forms;

using FlowLib.Connections;
using FlowLib.Containers;
using FlowLib.Interfaces;
using FlowLib.Events;
using FlowLib.Utils.Convert;
using FlowLib.Utils.Hash;
using FlowLib.Utils.Statistics;

using ClientExample.Containers;
using ClientExample.Client.Interface;
using ClientExample.Comparers;
using FlowLib.Containers.Security;

namespace ClientExample.Controls
{
    public partial class HubControl : ExpandablePanel, IBaseUpdater
    {
        public event FmdcEventHandler HubUpdate;
        public event FmdcEventHandler UpdateBase;
        protected delegate void UpdateViewDelegate();

        protected bool isUpdating = false;
        protected System.Windows.Forms.Timer updateTimer = new System.Windows.Forms.Timer();
        protected bool clearList = false;
        protected bool forceListPopulate = false;
        protected bool disableListPopulate = false;
        protected int connectionStatus = TcpConnection.Disconnected;
        protected int lastConnectionStatus = TcpConnection.Disconnected;
		protected bool isDisposed = false;
        protected long keepaliveInterval = 0;
        protected int selectedIndex = 0;
        protected long totalShared = 0;
        protected bool totalSharedIsDirty = false;

        protected static bool allowDraging = false;

        protected Tiger tiger = new Tiger();
        protected Hub connection = null;
        protected HubSetting setting = null;
        protected GeneralProtocolDataCollector stats = null;

        public string Id
        {
            get;
            protected set;
        }

        public new string Name
        {
            get;
            protected set;
        }

        public bool IsConnectionDisposing
        {
            get
            {
                return (connection != null && connection.IsDisposing);
            }
        }

        public bool IsConnectionDisposed
        {
            get
            {
                return (connection == null || connection.IsDisposed);
            }
        }

        public HubSetting Setting
        {
            get { return setting; }
            set
            {
                setting = value;
                if (connection == null)
                {
                    Id = string.Format("{0}:{1}", setting.Address, setting.Port);
                    Name = (setting.Name.Length > 0 ? setting.Name : Id);
                    TopLabel.Text = Name;
                }
                else
                    throw new InvalidOperationException("HubSetting can only be set once");
            }
        }

        public SortedList<string, User> Users
        {
            get 
            {
                return connection != null ? connection.Userlist : null;
            }
        }

        void connection_ConnectionStatusChange(object sender, FmdcEventArgs e)
        {
            HubUpdate(this, new FmdcEventArgs(EventActions.OnlineStatusChange, new OnlineStatus(Id, null, e.Action)));
            connectionStatus = e.Action;
            if (connectionStatus == TcpConnection.Disconnected)
            {
                clearList = true;
                totalShared = 0;
            }
        }

        void connection_ProtocolChange(object sender, FmdcEventArgs e)
        {
            Hub hubConnection = sender as Hub;
            IProtocol prot = e.Data as IProtocol;
            if (prot != null)
            {
                prot.Update -= Protocol_Update;
                if (Program.Settings.DebugMsg)
                {
                    prot.MessageReceived -= Protocol_MessageReceived;
                    prot.MessageToSend -= Protocol_MessageToSend;
                }
            }

            if (hubConnection != null)
            {
                hubConnection.Protocol.Update += new FmdcEventHandler(Protocol_Update);
                if (Program.Settings.DebugMsg)
                {
                    hubConnection.Protocol.MessageReceived += new FmdcEventHandler(Protocol_MessageReceived);
                    hubConnection.Protocol.MessageToSend += new FmdcEventHandler(Protocol_MessageToSend);
                }
            }
        }

        void Protocol_MessageToSend(object sender, FmdcEventArgs e)
        {
            StrMessage raw = e.Data as StrMessage;
            if (raw != null)
            {
                Message msg = new Message();
                msg.From = "OUT";
                msg.Content = raw.Raw;
                msg.GroupId = Id + "SEND";
                msg.GroupName = this.TopLabel.Text;
                msg.Status = new OnlineStatus(Id, "SEND", TcpConnection.Connected);
                HubUpdate(this, new FmdcEventArgs(Actions.MainMessage, msg));
            }
        }

        void Protocol_MessageReceived(object sender, FmdcEventArgs e)
        {
            StrMessage raw = e.Data as StrMessage;
            if (raw != null)
            {
                Message msg = new Message();
                msg.From = "IN";
                msg.Content = raw.Raw;
                msg.GroupId = Id + "SEND";
                msg.GroupName = this.TopLabel.Text;
                msg.Status = new OnlineStatus(Id, "RECV", TcpConnection.Connected);
                HubUpdate(this, new FmdcEventArgs(Actions.MainMessage, msg));
            }
        }

        void Protocol_Update(object sender, FmdcEventArgs e)
        {
            try
            {
                Message msg = null;
                Hub hubConnection = sender as Hub;
                User usr = null;

                if (hubConnection == null)
                    return;
                switch (e.Action)
                {
                    case Actions.MainMessage:
                        MainMessage msgMain = e.Data as MainMessage;
                        if (msgMain == null)
                            return;
                        msg = new Message();
                        if (!string.IsNullOrEmpty(msgMain.From))
                        {
                            usr = hubConnection.GetUserById(msgMain.From);
                            if (usr != null)
                                msg.From = usr.DisplayName;
                            else
                                msg.From = msgMain.From;
                        }
                        msg.Content = msgMain.Content;

                        msg.GroupId = Id;
                        // TODO : Add 
                        msg.GroupName = this.TopLabel.Text;
                        msg.Status = new OnlineStatus(Id, null, TcpConnection.Connected);
                        break;
                    case Actions.PrivateMessage:
                        PrivateMessage msgPM = e.Data as PrivateMessage;
                        if (msgPM == null)
                            return;
                        msg = new Message();
                        usr = hubConnection.GetUserById(msgPM.From);
                        msg.From = usr.DisplayName;

                        msg.To = msgPM.To;

                        if (msgPM.Content.StartsWith("<" + msgPM.From + "> "))
                            msg.Content = msgPM.Content.Substring(msgPM.From.Length + 3);
                        else
                            msg.Content = msgPM.Content;

                        string groupName = msg.From;
                        string groupId = msgPM.From;
                        if (hubConnection.Me.ID.Equals(msgPM.From) && (msgPM.Group == null || msgPM.From.Equals(msgPM.Group)))
                        {
                            usr = hubConnection.GetUserById(msgPM.To);
                            groupName = usr.DisplayName;
                            groupId = usr.ID;
                        }
                        else if (!string.IsNullOrEmpty(msgPM.Group))
                        {
                            usr = hubConnection.GetUserById(msgPM.Group);
                            groupName = usr.DisplayName;
                            groupId = usr.ID;
                        }
                        //else
                        //    groupId = groupName;

                        msg.GroupId = Id + groupId;
                        msg.GroupName = groupName;
                        msg.Status = new OnlineStatus(Id, groupId, TcpConnection.Connected);
                        break;
                    case Actions.UserInfoChange:
                        totalSharedIsDirty = true;
                        UserInfo infoChange = e.Data as UserInfo;
                        if (infoChange != null)
                        {
                            HubUpdate(this, new FmdcEventArgs(EventActions.UserInfoChanged, infoChange));
                            // TODO: Change this. It is ugly like hell...
                            listViewExtended1.AllItems.Remove(infoChange);
                            listViewExtended1.AllItems.Add(infoChange);
                        }
                        break;
                    case Actions.UserOnline:
                    case Actions.UserOffline:
                        UserInfo infoOnline = e.Data as UserInfo;
                        // Should we populate user list?
                            if (e.Action == Actions.UserOnline)
                            {
                                long tmpShare = 0;
                                if (long.TryParse(infoOnline.Share, out tmpShare))
                                {
                                    totalShared += tmpShare;
                                }
                            }
                            else
                            {
                                long tmpShare = 0;
                                if (long.TryParse(infoOnline.Share, out tmpShare))
                                {
                                    totalShared -= tmpShare;
                                }
                            }
                            if (!disableListPopulate)
                            {
                                if (e.Action == Actions.UserOnline)
                                {
                                    listViewExtended1.AllItems.Add(infoOnline);
                                }
                                else
                                {
                                    listViewExtended1.AllItems.Remove(infoOnline);
                                }
                            }
                            if (infoOnline != null)
                            {
                                int status = (e.Action == Actions.UserOnline ? TcpConnection.Connected : TcpConnection.Disconnected);
                                HubUpdate(this, new FmdcEventArgs(EventActions.OnlineStatusChange, new OnlineStatus(Id, infoOnline.ID, infoOnline.StoreID, status)));
                            }
                        break;
                    case Actions.SearchResult:
                    case Actions.TransferRequest:
                    case Actions.TransferStarted:
                        HubUpdate(this, e);
                        break;
                }

                if (msg != null)
                {
                    HubUpdate(this, new FmdcEventArgs(e.Action, msg));
                }
            }
            catch
            {
                // TODO : Add Error handling here
            }
        }

        protected void OnRedrawList()
        {
            listViewExtended1.Invalidate(true);
        }

        public void SendSearch(SearchInfo info)
        {
            if (this.connectionStatus == TcpConnection.Connected)
                UpdateBase(this, new FlowLib.Events.FmdcEventArgs(Actions.Search, info));
        }

        public void SendMessage(Message msg)
        {
            if (msg.Status.HubId.Equals(Id))
            {
                if (string.IsNullOrEmpty(msg.Status.UserId))
                {
                    // Main chat
                    UpdateBase(this, new FmdcEventArgs(Actions.MainMessage, new MainMessage(connection.Me.ID, msg.Content)));
                }
                else
                {
                    // PM
                    UpdateBase(this, new FmdcEventArgs(Actions.PrivateMessage, new PrivateMessage(msg.Status.UserId, connection.Me.ID, msg.Content)));
                }
            }
        }

        public HubControl()
			: base()
        {
			IntPtr h = Handle;  // This is for stupid mono stuff. Some how handle isnt created correctly if we dont do this :(
            InitializeComponent();

            Hub.RegModeUpdated += new FmdcEventHandler(Hub_RegModeUpdated);

            UpdateBase = new FmdcEventHandler(HubControl_UpdateBase);
            HubUpdate = new FmdcEventHandler(HubControl_Update);

            listViewExtended1.ItemSelectionChanged += new System.Windows.Forms.ListViewItemSelectionChangedEventHandler(listViewExtended1_ItemSelectionChanged);

            sendMessageToToolStripMenuItem.Image = Program.Images.GetBitmap("pen.gif");
			
			this.Disposed +=new EventHandler(OnDisposed);

            base.ExpandedChanged += new EventHandler<FmdcEventArgs<int, object>>(HubControl_ExpandedChanged);
            label1.MouseClick += new System.Windows.Forms.MouseEventHandler(label1_MouseClick);
            label1.MouseEnter += new EventHandler(label1_MouseEnter);
            label1.Width = 180;
            // This is for hub reordering
            AllowDrop = true;
            label1.MouseDown += new System.Windows.Forms.MouseEventHandler(OnMouseDown);
            menuStripHub.Opening += new CancelEventHandler(OnMenuStripHubOpening);

            updateTimer.Tick += new EventHandler(updateTimer_Tick);
            updateTimer.Interval = 50;
            updateTimer.Start();
        }

        public void FireHubUpdate(FmdcEventArgs e)
        {
            HubUpdate(this, e);
        }

        public void FireUpdateBase(FmdcEventArgs e)
        {
            UpdateBase(this, e);
        }

        void OnMouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (allowDraging && e.Button== System.Windows.Forms.MouseButtons.Left)
            {
                DoDragDrop(this, System.Windows.Forms.DragDropEffects.Move);
            }
        }

        void OnMenuStripHubOpening(object sender, CancelEventArgs e)
        {
            changeHubOrderToolStripMenuItem.Checked = allowDraging;
        }

        protected override void OnDragOver(System.Windows.Forms.DragEventArgs e)
        {
            base.OnDragOver(e);
            // is another dragable
            HubControl otherHub = null;
            if ((otherHub = (HubControl)e.Data.GetData(typeof(HubControl))) != null)
            {
                System.Windows.Forms.FlowLayoutPanel panel = Parent as System.Windows.Forms.FlowLayoutPanel;
                if (panel != null)
                {
                    e.Effect = System.Windows.Forms.DragDropEffects.Move;
                    try
                    {
                        int index = panel.Controls.GetChildIndex(this);
                        Program.Settings.SavedHubs.Remove(otherHub.setting);
                        panel.Controls.SetChildIndex((System.Windows.Forms.Control)e.Data.GetData(typeof(HubControl)), index);
                        Program.Settings.SavedHubs.Insert(index, otherHub.Setting);
                        Program.Save();
                    }
                    catch
                    {
                        if (!Program.Settings.SavedHubs.Contains(otherHub.Setting))
                        {
                            Program.Settings.SavedHubs.Add(otherHub.Setting);
                            Program.Save();
                        }
                    }
                }
            }
        }

        void label1_MouseEnter(object sender, EventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            if (lastConnectionStatus == TcpConnection.Connected)
            {
                if (totalSharedIsDirty)
                {
                    //sb.AppendLine("Update in progress. Check again later");
                    //System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(CalculateTotalShare));
                    //t.IsBackground = true;
                    //t.Start();
                    CalculateTotalShare();
                }
                FlowLib.Utils.Convert.General.BinaryPrefixes bp;
                //sb.AppendLine(string.Format("Bytes received: {0} {1}", FlowLib.Utils.Convert.General.FormatBytes(stats.TotalBytesReceived, out bp), bp));
                //sb.AppendLine(string.Format("Bytes sent: {0} {1}", FlowLib.Utils.Convert.General.FormatBytes(stats.TotalBytesSent, out bp), bp));
                sb.AppendLine("Encryption: " + connection.SecureProtocol.ToString());
                sb.AppendLine("Online users: " + connection.Userlist.Count);
                sb.AppendLine(string.Format("Total share: {0} {1}", FlowLib.Utils.Convert.General.FormatBytes(totalShared, out bp), bp));

            }
            else
            {
                sb.AppendLine("No information available");
            }
            toolTipName.SetToolTip(label1, sb.ToString());

        }

        protected void CalculateTotalShare()
        {
            totalShared = 0;
            totalSharedIsDirty = false;
            long tmpTotalShared = 0;
            try
            {
                lock (connection.Userlist)
            	{
                    SortedList<string, User> tmpUserlist = connection.Userlist;
                    foreach (KeyValuePair<string, User> item in tmpUserlist)
	                {
                        long lng = 0;
                        if (long.TryParse(item.Value.UserInfo.Share, out lng))
                        {
                            tmpTotalShared += lng;
                        }
	                }
                    totalShared = tmpTotalShared;
	            }
            }
            catch
            {

            }
        }

        void Hub_RegModeUpdated(object sender, FmdcEventArgs e)
        {
            Hub hub = sender as Hub;
            if (e.Action >= 0)
            {
                if (hub != null && hub.Me != null && hub.Me.ContainsKey(UserInfo.PID))
                {
                    Program.Settings.PID = hub.Me.Get(UserInfo.PID);
                }
            }
        }

        void listViewExtended1_ItemSelectionChanged(object sender, System.Windows.Forms.ListViewItemSelectionChangedEventArgs e)
        {
            if (e.IsSelected)
            {
                selectedIndex = e.ItemIndex;
            }
        }
		
		void OnDisposed(object sender, System.EventArgs e)
		{
			isDisposed = true;
			updateTimer.Stop();
			updateTimer.Dispose();
            if (stats != null)
            {
                stats.Dispose();
                stats = null;
            }
		}

        void label1_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                menuStripHub.Show(MousePosition.X, MousePosition.Y);
            }
        }

        void HubControl_ExpandedChanged(object sender, FmdcEventArgs<int, object> e)
        {
            if (e.Action > this.Height)
            {
                listViewExtended1.AllItems.Clear();
                clearList = true;
                disableListPopulate = true;
            }
            else
            {
                disableListPopulate = false;
                forceListPopulate = true;
            }
        }

        void updateTimer_Tick(object sender, EventArgs eTimer)
        {
            if (isUpdating)
                return;
			
            isUpdating = true;

            if (setting != null && connection == null)
            {
                try
                {
                    connection = new Hub(setting, this);
                    stats = new GeneralProtocolDataCollector(connection);
                    connection.Me.TagInfo.Version = "Xmpl V:" + Program.Settings.Version;
                    connection.Me.TagInfo.Slots = 2;
                    //connection.Share = new Share("TEMP");
                    connection.Share = Program.Shares.Default;
                    // We want to keep the same CID between connections and hubs.
                    if (!string.IsNullOrEmpty(Program.Settings.PID))
                    {
                        connection.Me.Set(UserInfo.PID, Program.Settings.PID);
                    }

                    if (Program.Settings.ConnectionMode == 2)
                    {
                        connection.Me.Mode = FlowLib.Enums.ConnectionTypes.Direct;
                        connection.Me.Set(UserInfo.IP, Program.Settings.IP);
                    }

                    connection.ProtocolChange += new FlowLib.Events.FmdcEventHandler(connection_ProtocolChange);
                    connection.ConnectionStatusChange += new FmdcEventHandler(connection_ConnectionStatusChange);
                    connection.SecureUpdate += new FmdcEventHandler(connection_SecureUpdate);
                    if (setting.ContainsKey("QuickConnect"))
                    {
                        setting.Remove("QuickConnect");
                        connection.Connect();
                    }
                    else if (setting.ContainsKey("Connect"))
                    {
                        switch (setting.Get("Connect").ToLower())
                        {
                            case "1":   // Auto connect to hub
                                connection.Connect();
                                break;
                        }
                    }
                }
                catch { /* Invalid addy */ }
            }

            if (connectionStatus != lastConnectionStatus)
            {
                switch (connectionStatus)
                {
                    case TcpConnection.Connecting:
                        TopLabel.ForeColor = Color.Orange;
                        sendMessageToolStripMenuItem.Enabled = false;
                        disconnectToolStripMenuItem.Visible = false;
                        reconnectToolStripMenuItem.Visible = true;
                        break;
                    case TcpConnection.Connected:
                        TopLabel.ForeColor = Color.Green;
                        sendMessageToolStripMenuItem.Enabled = true;
                        disconnectToolStripMenuItem.Visible = true;
                        reconnectToolStripMenuItem.Visible = false;
                        break;
                    case TcpConnection.Disconnected:
                        TopLabel.ForeColor = Color.Gray;
                        sendMessageToolStripMenuItem.Enabled = false;
                        disconnectToolStripMenuItem.Visible = false;
                        reconnectToolStripMenuItem.Visible = true;
                        break;
                    default:
                        break;
                }
                lastConnectionStatus = connectionStatus;
            }

            if (clearList)
            {
                //users.Clear();
                listViewExtended1.AllItems.Clear();
                clearList = false;
            }
            if (disableListPopulate)
            {
                isUpdating = false;
                return;
            }

            if (forceListPopulate && connection != null)
            {
                listViewExtended1.AllItems.Clear();
                try
                {
                    SortedList<string, User> userList = new SortedList<string, User>(connection.Userlist);
                    if (userList.Count > 0)
                    {
                        foreach (KeyValuePair<string, User> userPair in userList)
                        {
                            listViewExtended1.AllItems.Add(userPair.Value.UserInfo);
                        }
                    }
                    else
                    {
                        // TODO : Add message about that we are waiting for users from hub
                    }
                    forceListPopulate = false;
                }
                catch (IndexOutOfRangeException)
                {
                    // TODO : Why in hell do this happen? Fix it!
                }
            }

            // Update User count
            // TODO : REMOVE THIS
            listViewExtended1.VirtualListSize = listViewExtended1.Items.Count;
            isUpdating = false;
        }

        void connection_SecureUpdate(object sender, FmdcEventArgs e)
        {
            CertificateValidationInfo info = e.Data as CertificateValidationInfo;
            if (info != null)
            {
                info.Accepted = true;
            }
        }

        protected void HubControl_Update(object sender, FmdcEventArgs e) { }
        protected void HubControl_UpdateBase(object sender, FmdcEventArgs e) { }
        protected void HubControl_Load(object sender, EventArgs e) { }

        private void reconnectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            connection.Reconnect();
            if (keepaliveInterval != 0)
                connection.KeepAliveInterval = keepaliveInterval;
        }

        private void disconnectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            keepaliveInterval = connection.KeepAliveInterval;
            connection.KeepAliveInterval = 0;
            connection.Disconnect("User aborted connection");
        }

        private void sendMessageToToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (listViewExtended1.Items.Count > selectedIndex)
            {
                UserInfo usr = listViewExtended1.Items[selectedIndex];
                Message msg = new Message();
                msg.IsSystem = true;
                msg.To = usr.ID;
                msg.GroupId = Id + usr.ID;
                msg.GroupName = usr.DisplayName;
                msg.Content = "Do not write sensitive information like pay card nr and more here. It can be gathered by others.";
                msg.Status = new OnlineStatus(Id, usr.ID, usr.StoreID, TcpConnection.Connected);
                HubUpdate(this, new FmdcEventArgs(EventActions.ForceOpenMessage, msg));

            }
        }

        private void sendMessageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (connectionStatus == TcpConnection.Connected)
            {
                Message msg = new Message();
                msg.IsSystem = true;
                msg.GroupId = Id;
                msg.GroupName = TopLabel.Text;
                msg.Content = "Do not write sensitive information like pay card nr and more here. It can be gathered by others.";
                msg.Status = new OnlineStatus(Id, null, TcpConnection.Connected);
                HubUpdate(this, new FmdcEventArgs(EventActions.ForceOpenMessage, msg));
            }
        }

        private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            HubSettingsWindow dlg = new HubSettingsWindow();
            dlg.Settings = setting;
            if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                //connection.Disconnect();
                HubUpdate(this, new FmdcEventArgs(EventActions.SettingsChange, Id));
                if (connection != null)
                {
                    connection.Dispose();
                }
                connection = null;
                Setting = dlg.Settings;

                Program.Save();
            }
            else if (dlg.DialogResult == System.Windows.Forms.DialogResult.Ignore)
            {
                Visible = false;
                connection.Dispose();
                HubUpdate(this, new FmdcEventArgs(EventActions.Close));
                Program.Settings.SavedHubs.Remove(setting);
                Program.Save();
                Dispose();
            }
        }

        private void changeHubOrderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            allowDraging = changeHubOrderToolStripMenuItem.Checked;
        }

        private void addToFriendsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (listViewExtended1.Items.Count > selectedIndex)
            {
                UserInfo usr = listViewExtended1.Items[selectedIndex];
                Friend friend = new Friend(usr);

                FlowLib.Utils.Hash.Tiger tiger = new FlowLib.Utils.Hash.Tiger();
                tiger.Initialize();
                string hubid = FlowLib.Utils.Convert.Base32.Encode(tiger.ComputeHash(System.Text.Encoding.UTF8.GetBytes(Id)));
                tiger.Clear();
                friend.Set(hubid, usr.ID);
                friend.Set("HUBS", hubid + "." + friend.Get("HUBS"));
                friend.OnlineStatus = TcpConnection.Connected;
                Program.Settings.SavedFriends.Add(friend);
            }
        }

        private void downloadFilelistToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (listViewExtended1.Items.Count > selectedIndex)
            {
                UserInfo usr = listViewExtended1.Items[selectedIndex];
                Source src = new Source(Id, usr.StoreID);
                Program.Transfers.AddFilelist(src, false);
                // Start downloading
                UpdateBase(this, new FmdcEventArgs(Actions.StartTransfer, usr));
            }
        }
    }
}
